﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using GameCore;
using Object = UnityEngine.Object;

namespace GameLogic
{
    /// <summary>
    /// AB文件加载器
    /// @author:dingjie
    /// </summary>
    public class AssetBundleLoader
    {
        public class ABLoaderEvent : UnityEvent<AssetBundleLoader> { };
        /// <summary>
        /// AB文件加载状态
        /// </summary>
        public enum ABLoaderState
        {
            //等待中
            Wait,
            //加载中
            Loading,
            //加载成功
            Success,
            //加载失败
            Failed
        }
        /// <summary>
        /// 路径
        /// </summary>
        protected string path;
        /// <summary>
        /// 用于加载的路径
        /// </summary>
        protected string fullPath;
        /// <summary>
        /// AB文件
        /// </summary>
        protected AssetBundle assetBundle;
        /// <summary>
        /// 加载完成回调
        /// </summary>
        protected ABLoaderEvent onLoadFinish;
        /// <summary>
        /// 卸载回调
        /// </summary>
        protected Action<string> unLoadAction;
        /// <summary>
        /// 依赖
        /// </summary>
        protected string[] dependences;
        /// <summary>
        /// 引用
        /// </summary>
        protected List<string> references;
        /// <summary>
        /// 是否加载完成
        /// </summary>
        protected bool isLoadFinish;
        /// <summary>
        /// 进度
        /// </summary>
        protected float progress;
        /// <summary>
        /// 加载状态
        /// </summary>
        protected ABLoaderState abLoaderState = ABLoaderState.Wait;
        /// <summary>
        /// 优先级,值越大越优先加载
        /// </summary>
        protected int priority;
        /// <summary>
        /// 是否为全局的
        /// </summary>
        protected bool isGlobal;
        /// <summary>
        /// 生命周期剩余
        /// </summary>
        protected int leftLife;

        /// <summary>
        /// 依赖
        /// </summary>
        public string[] Dependences
        {
            get
            {
                return dependences;
            }
        }

        /// <summary>
        /// 引用
        /// </summary>
        public List<string> References
        {
            get
            {
                return references;
            }
        }

        /// <summary>
        /// ABLoader状态
        /// </summary>
        public ABLoaderState AbLoaderState
        {
            get
            {
                return abLoaderState;
            }
        }

        /// <summary>
        /// 是否加载完成
        /// </summary>
        public bool IsLoadFinish
        {
            get
            {
                return isLoadFinish;
            }
        }

        /// <summary>
        /// 路径
        /// </summary>
        public string Path
        {
            get
            {
                return path;
            }
        }

        /// <summary>
        /// 是否为全局AB包，全局AB包不会被自动卸载
        /// </summary>
        public bool IsGlobal
        {
            get
            {
                return isGlobal;
            }

            set
            {
                isGlobal = value;
            }
        }

        /// <summary>
        /// 剩余生命周期
        /// </summary>
        public int LeftLife
        {
            get
            {
                return leftLife;
            }

            set
            {
                leftLife = value;
            }
        }

        public float Progress
        {
            get
            {
                return progress;
            }
        }



        /// <summary>
        /// AB文件加载器
        /// </summary>
        /// <param name="path"></param>
        /// <param name="dependences"></param>
        public AssetBundleLoader()
        {
            references = new List<string>();
            onLoadFinish = new ABLoaderEvent();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="path">加载路径</param>
        /// <param name="dependences">依赖</param>
        public void Init(string path, string fullPath, string[] dependences)
        {
            this.path = path;
            this.fullPath = fullPath;
            this.dependences = dependences;
            this.abLoaderState = ABLoaderState.Wait;
        }

        /// <summary>
        /// 添加加载完成回调
        /// </summary>
        /// <param name="action"></param>
        public void AddListener(UnityAction<AssetBundleLoader> action)
        {
            this.onLoadFinish.AddListener(action);
        }

        public void SetUnLoadAction(Action<string> unLoadAction)
        {
            this.unLoadAction = unLoadAction;
        }

        /// <summary>
        /// 添加依赖
        /// </summary>
        /// <param name="bundleName"></param>
        public void AddReference(string bundleName)
        {
            references.Add(bundleName);
        }




        /// <summary>
        /// 移除依赖
        /// </summary>
        /// <param name="bundleName"></param>
        public void RemoveReference(string bundleName)
        {
            references.Remove(bundleName);
            if (!isGlobal && references.Count == 0)
            {
                UnLoad();
            }
        }
        /// <summary>
        /// 加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetName"></param>
        /// <returns></returns>
        public T LoadAsset<T>(string assetName) where T : Object
        {
            GameCore.Logger.Log ("LoadAsset:"+ assetName + "  Type:" + typeof(T).FullName);
            if (assetBundle != null)
            {
                UnityEngine.Profiling.Profiler.BeginSample("LoadAsset:" + path);
                T t = assetBundle.LoadAsset<T>(assetName);
                UnityEngine.Profiling.Profiler.EndSample();
                return t;
            }
            return null;
        }

        /// <summary>
        /// 加载所有资源
        /// </summary>
        public Object[] LoadAllAsset()
        {
            if (assetBundle != null)
            {
                UnityEngine.Profiling.Profiler.BeginSample("LoadAllAsset:" + path);
                Object[] objs = assetBundle.LoadAllAssets();
                UnityEngine.Profiling.Profiler.EndSample();
                return objs;
            }
            return null;
        }

        /// <summary>
        /// 加载所有资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T[] LoadAllAsset<T>() where T : Object
        {
            if (assetBundle != null)
            {
                UnityEngine.Profiling.Profiler.BeginSample("LoadAllAsset<T>:" + path);
                T[] ts = assetBundle.LoadAllAssets<T>();
                UnityEngine.Profiling.Profiler.EndSample();
                return ts;
            }
            return null;
        }

        /// <summary>
        /// 加载AB文件
        /// </summary>
        virtual public bool LoadAssetBundle()
        {
            GameCore.Logger.Log("LoadAssetBundle:" + path);
            UnityEngine.Profiling.Profiler.BeginSample("LoadAssetBundle:" + path);
            assetBundle = AssetBundle.LoadFromFile(fullPath);
            UnityEngine.Profiling.Profiler.EndSample();
            if (assetBundle != null)
            {
                LoadOver();
                return true;
            }
            else
            {
                GameCore.Logger.LogError("同步加载失败:AssetBundle:"+ path);
                LoadFailed();
                return false;
            }

        }
        /// <summary>
        /// 异步加载AB文件
        /// </summary>
        /// <returns></returns>
        virtual public IEnumerator LoadAssetBundleAsyn()
        {
            GameCore.Logger.Log("LoadAssetBundleAsyn:" + path);
            abLoaderState = ABLoaderState.Loading;
            AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(fullPath);
            while (!request.isDone)
            {
                progress = request.progress;
                yield return null;
            }
            if (request.assetBundle != null)
            {
                assetBundle = request.assetBundle;
                LoadOver();
            }
            else
            {
                GameCore.Logger.LogErrorFormat("异步加载AB失败!,AssetBundle:", path);
                LoadFailed();
            }
        }

        /// <summary>
        /// 加载完成
        /// </summary>
        protected void LoadOver()
        {
            abLoaderState = ABLoaderState.Success;
            isLoadFinish = true;
            progress = 1f;
            onLoadFinish.Invoke(this);
        }


        /// <summary>
        /// 加载失败
        /// </summary>
        protected void LoadFailed()
        {
            abLoaderState = ABLoaderState.Failed;
            isLoadFinish = true;
            progress = 1f;
            onLoadFinish.Invoke(this);
        }


        /// <summary>
        /// 卸载AB文件
        /// </summary>
        public void UnLoad()
        {
            GameCore.Logger.Log("UnLoadAssetBundle:"+ path);
            if (assetBundle != null)
                assetBundle.Unload(false);
        }

        /// <summary>
        /// 清理方法，回收的时候调用
        /// </summary>
        public void Clear()
        {
            priority = 0;
            progress = 0f;
            isLoadFinish = false;
            onLoadFinish.RemoveAllListeners();
            assetBundle = null;
            unLoadAction = null;
            dependences = null;
            references.Clear();
            isGlobal = false;
        }
    }

}
